import 'dart:convert';
import 'dart:io';

import 'package:audioplayers/audioplayers.dart';
import 'package:flutter_audio_query/flutter_audio_query.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:freemusic/model/AbstractSong.dart';
import 'package:freemusic/model/KugouSong.dart';
import 'package:freemusic/model/LocalSong.dart';
import 'package:freemusic/model/NeteaseSong.dart';
import 'package:freemusic/model/QQSong.dart';
import 'package:freemusic/model/migu/MiguSong.dart';
import 'package:freemusic/services/AbstractServices.dart';
import 'package:freemusic/stores/SongStores.dart' as songStores;
import 'package:freemusic/utils/SQFLite.dart';
import 'package:freemusic/utils/request/Request.dart' as request;
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:freemusic/stores/PlayerStores.dart' as playerStores;

class SongServices extends AbstractServices {
  static SongServices _instance;
  static SQFLiteUtil _sqfLiteUtil;
  static AudioPlayer _audioPlayer;
  final String KEYWORDS = "keywords";
  final String temp_paly_list_key = "temp_play_list:";
  final String recently_paly_list_key = "recently_paly_list:";
  final int recentlyPlayLength = 200;
  final String root_save_path = "/storage/emulated/0/freemusic";

  SongServices._();

  static SongServices getInstace() {
    if (_instance == null) {
      _instance = SongServices._();
    }
    if (_sqfLiteUtil == null) {
      _instance._init();
    }

    return _instance;
  }

  void _init() {
    SQFLiteUtil.getInstance().then((v) {
      _sqfLiteUtil = v;
    });
    _audioPlayer = AudioPlayer(mode: PlayerMode.MEDIA_PLAYER)
      ..onPlayerStateChanged.listen((state) {
        if (state == AudioPlayerState.COMPLETED) {
          playerStores.completPlay();
        }
      });
  }

  AudioPlayer get audioPlayer => _audioPlayer;

  void seek(Duration position) {
    Future.delayed(Duration(milliseconds: 140), () {
      _audioPlayer.seek(position);
    });
  }

  void search(String keyword) async {
    //将keyword 放到 搜索历史缓存中
    SharedPreferences.getInstance().then((spf) {
      List<String> keywords = spf.getStringList(KEYWORDS);
      if (keywords == null) {
        keywords = List();
      }
      if (keywords.length >= 10) {
        keywords.removeAt(0);
      }
      int index = keywords.indexWhere((item) => item == keyword);
      if (index == -1) {
        keywords.add(keyword);
      }
      spf.setStringList(KEYWORDS, keywords);
      songStores.putKeyword(keyword);
    });

    List<KugouSong> kugouSongs =
        await request.search(SongPlatform.kugou, keyword, 1);
    songStores.changeKugouList(kugouSongs);
    List<QQSong> qqSongs = await request.search(SongPlatform.qq, keyword, 1);
    songStores.changeQQList(qqSongs);
    List<NeteaseSong> neteaseSongs =
        await request.search(SongPlatform.netease, keyword, 1);
    songStores.changeNeteaseList(neteaseSongs);
    List<MiguSong> migusongs =
        await request.search(SongPlatform.migu, keyword, 1);
    songStores.changeMiguList(migusongs);
  }

  Future<int> searchByPage(String platform, String keyword, int page) async {
    int count = 0;
    switch (platform.toLowerCase()) {
      case "kugou":
        List<KugouSong> kugouSongs =
            await request.search(SongPlatform.kugou, keyword, page);
        count = kugouSongs.length;
        songStores.appendKugouList(kugouSongs);
        break;
      case "qq":
        List<QQSong> qqSongs =
            await request.search(SongPlatform.qq, keyword, page);
        count = qqSongs.length;
        songStores.appendQQList(qqSongs);
        break;
      case "netease":
        List<NeteaseSong> neteaseSongs =
            await request.search(SongPlatform.netease, keyword, page);
        count = neteaseSongs.length;
        songStores.appendNeteaseList(neteaseSongs);
        break;
      case "migu":
        List<MiguSong> miguSongs =
            await request.search(SongPlatform.migu, keyword, page);
        count = miguSongs.length;
        songStores.appendMiguList(miguSongs);
        break;
    }
    return count;
  }

  void emptySongList() {
    songStores.changeKugouList([]);
    songStores.changeQQList([]);
    songStores.changeNeteaseList([]);
  }

  void deleteAllKerwordHistory() {
    SharedPreferences.getInstance().then((spf) {
      spf.remove(KEYWORDS);
      songStores.putKeywords([]);
    });
  }

//获取搜索历史
  void loadKerwordHistory() {
    SharedPreferences.getInstance().then((spf) {
      List<String> keywords = spf.getStringList(KEYWORDS);
      if (keywords != null) {
        songStores.putKeywords(keywords);
      }
    });
  }

  void playSong(AbstractSong info) {
    if (info.isLocal) {
      if (_playLocalSong(info.playUrl)) {
        //songinfo 放入到store中
        playerStores.playSong(info);
        //songinfo 放入到缓存中
        _putTempSong(info);
        //songinfo 放入到最近播放200首中
        _putRecentlyPaly(info);
      } else {
        Fluttertoast.showToast(msg: "播放失败，本地文件可能已被删除");
      }
      return;
    }
    //先查询歌曲信息
    request.getSong(info).then((songInfo) {
      String playUrl = songInfo.playUrl;
      if (playUrl == null || playUrl.isEmpty) {
        Fluttertoast.showToast(msg: "未获取到播放地址，请试试其他平台");
        return;
      }
      //查看本地是否有缓存，有缓存播放本地，否则先缓存到本地，然后再播放.
      Future<Directory> tempDirFuture = getTemporaryDirectory();
      tempDirFuture.then((tempDir) {
        String path = "${tempDir.path}/${songInfo.hash}.${songInfo.type}";

        if (!_playLocalSong(path)) {
          _playNetWorkSong(path, songInfo);
        }
        //songinfo 放入到store中
        playerStores.playSong(songInfo);
        //songinfo 放入到缓存中
        _putTempSong(songInfo);
        //songinfo 放入到最近播放200首中
        _putRecentlyPaly(songInfo);
      });
    });
  }

  bool _playLocalSong(String path) {
    File file = File(path);
    if (file.existsSync()) {
      _audioPlayer.play(file.path, isLocal: true);
      return true;
    } else {
      return false;
    }
  }

  void _playNetWorkSong(String savepath, AbstractSong info) {
    //先缓存到本地，然后播放本地文件
    if (info.playUrl.isNotEmpty) {
      _audioPlayer.play(info.playUrl);
      request.downloadSong(info.platform, info.playUrl, savepath);
    }
  }

  //播放列表歌曲
  void _putTempSong(AbstractSong song) {
    SharedPreferences.getInstance().then((spf) {
      String key = temp_paly_list_key + song.hash;
      if (!spf.containsKey(key)) {
        spf.setString(key, song.toJsonString());
      }
    });
  }

  //播放列表歌曲
  void changeTempSongList(List<AbstractSong> songs) {
    SharedPreferences.getInstance().then((spf) {
      Iterable<String> tempSongKeys =
          spf.getKeys().where((item) => item.startsWith(temp_paly_list_key));
      tempSongKeys.forEach((v) {
        spf.remove(v);
      });
      songs.forEach((item) {
        _putTempSong(item);
      });
    });
  }

  void _putRecentlyPaly(AbstractSong song) {
    SharedPreferences.getInstance().then((spf) {
      Iterable<String> recentlykeys = spf
          .getKeys()
          .where((item) => item.startsWith(recently_paly_list_key));
      if (recentlykeys.length >= recentlyPlayLength) {
        return;
      }

      String key = recently_paly_list_key + song.hash;
      if (!spf.containsKey(key)) {
        spf.setString(key, song.toJsonString());
      }
      songStores.appendRecentSong(song);
    });
  }

  void loadTempSongList() {
    SharedPreferences.getInstance().then((spf) {
      List<AbstractSong> songinfos = List();
      Iterable<String> tempSongKeys =
          spf.getKeys().where((item) => item.startsWith(temp_paly_list_key));
      tempSongKeys.forEach((v) {
        String value = spf.getString(v);
        final map = jsonDecode(value);
        String platform = map['platform'];
        AbstractSong info;
        switch (platform) {
          case "kugou":
            info = KugouSong();
            break;
          case "qq":
            info = QQSong();
            break;
          case "netease":
            info = NeteaseSong();
            break;
          case "local":
            info = LocalSong();
            break;
          case "migu":
            info = MiguSong();
        }
        info.fromDataBase(map);
        songinfos.add(info);
        playerStores.initSongSheet(songinfos);
      });
    });
  }

  void nextSong() {
    playerStores.nextPlay();
  }

  void prevSong() {
    playerStores.previousPlay();
  }

  void changePlaying(bool playing) {
    if (playing) {
      _audioPlayer.resume();
    } else {
      _audioPlayer.pause();
    }
    playerStores.changePlaying(playing);
  }

  //清空当前播放列表
  void clearStorePlayList() async {
    SharedPreferences spf = await SharedPreferences.getInstance();
    Iterable<String> tempSongKeys =
        spf.getKeys().where((item) => item.startsWith(temp_paly_list_key));
    tempSongKeys.forEach((v) {
      spf.remove(v);
    });
    playerStores.changeSongSheet(List());
  }

//删除播放列表中的歌曲
  void deleteStorePlaySong(AbstractSong song) {
    SharedPreferences.getInstance().then((spf) {
      String key = temp_paly_list_key + song.hash;
      spf.remove(key);
      playerStores.deleteSong(song);
    });
  }

  void changePlayModel() {
    playerStores.changePlayModel();
  }

  void addNextPlay(AbstractSong song) {
    playerStores.addNextPlay(song);
    _putTempSong(song);
  }

  //加载最近播放的音乐
  Future<List<AbstractSong>> loadRecentPlaySong() async {
    SharedPreferences spf = await SharedPreferences.getInstance();
    List<AbstractSong> songinfos = List();
    Iterable<String> tempSongKeys =
        spf.getKeys().where((item) => item.startsWith(recently_paly_list_key));
    tempSongKeys.forEach((v) {
      String value = spf.getString(v);
      final map = jsonDecode(value);
      String platform = map['platform'];
      AbstractSong info;
      switch (platform) {
        case "kugou":
          info = KugouSong();
          break;
        case "qq":
          info = QQSong();
          break;
        case "netease":
          info = NeteaseSong();
          break;
      }
      info.fromDataBase(map);
      songinfos.add(info);
    });
    return songinfos;
  }

  Future<bool> clearAllRecentSong() async {
    SharedPreferences spf = await SharedPreferences.getInstance();
    Iterable<String> tempSongKeys =
        spf.getKeys().where((item) => item.startsWith(recently_paly_list_key));
    tempSongKeys.forEach((v) {
      spf.remove(v);
    });
    songStores.changeRecentSongList([]);
    return true;
  }

  Future<bool> deleteRecentSong(String hash) async {
    SharedPreferences spf = await SharedPreferences.getInstance();
    String key = recently_paly_list_key + hash;
    spf.remove(key);
    songStores.deleteRecentSong(hash);
    return true;
  }

  Future<bool> _loadLocalSongs() async {
    bool permissionFlat =
        await _handlePermissionBeforeLoad(PermissionGroup.storage);
    if (permissionFlat) {
      _handleLoadLocalSongs();
    }
    return true;
  }

  void loadLocalSongs() async {
    _loadLocalSongs();
  }

  Future<bool> _handlePermissionBeforeLoad(
      PermissionGroup permissionGroup) async {
    PermissionHandler permissionHandler = PermissionHandler();
    PermissionStatus status =
        await permissionHandler.checkPermissionStatus(permissionGroup);
    if (status != PermissionStatus.granted) {
      Map<PermissionGroup, PermissionStatus> permissions =
          await permissionHandler.requestPermissions([PermissionGroup.storage]);
      status = permissions[permissionGroup];
      if (status == PermissionStatus.denied) {
        return false;
      }
    }
    return true;
  }

  void _handleLoadLocalSongs() {
    FlutterAudioQuery().getSongs().then((list) {
      List<LocalSong> localsongs = List();
      list.forEach((SongInfo songInfo) {
        if (!songInfo.isMusic) {
          return;
        }
        String songName = songInfo.displayName;
        String type = songName.substring(songName.lastIndexOf(".") + 1);
        if (type == "ogg") {
          return;
        }
        LocalSong song = LocalSong();

        song.hash = songInfo.hashCode.toString();
        song.platform = SongPlatform.local;
        song.playUrl = songInfo.filePath;
        song.songName = songName;
        song.singerName = songInfo.artist;
        song.timeLength = Duration(milliseconds: int.parse(songInfo.duration));
        song.type = type;
        song.isLocal = true;
        song.lyrics = "";
        localsongs.add(song);
      });
      songStores.changeLocalSongList(localsongs);
    });
  }

  void deleteLocalSong(AbstractSong song) {
    File file = File(song.playUrl);
    if (file.existsSync()) {
      file.delete(recursive: true);
    }
    songStores.deleteLocalSong(song);
  }

  //播放列表中的所有歌曲
  void playListAllSong(List<AbstractSong> songs) {
    playerStores.changeSongSheet(songs);
    SongServices.getInstace().changeTempSongList(songs);
  }

  //清理缓存
  Future<bool> cleanLocalCache() async {
    //清理歌曲缓存
    Directory tempDirFuture = await getTemporaryDirectory();
    tempDirFuture.listSync().forEach((v) {});
    await tempDirFuture.delete(recursive: true);
    return true;
  }

  void downloadSong(AbstractSong song) async {

    bool beforeDownload = await _beforeDownloadSong(song);
    if(!beforeDownload) {
      Fluttertoast.showToast(msg: "未获取到播放地址，请试试其他资源");
      return ;
    }

    bool permissionFlat =
        await _handlePermissionBeforeLoad(PermissionGroup.storage);
    if (permissionFlat) {
      Fluttertoast.showToast(msg: "正在下载...");
      Directory rootDir = Directory(root_save_path);
      if (!rootDir.existsSync()) {
        rootDir.createSync();
      }
      String fileName = "${song.songName} - ${song.singerName}.mp3";
      String savepath = "$root_save_path/$fileName";
      request
          .downloadSong(song.platform, song.playUrl, savepath)
          .then((reslut) {
        Fluttertoast.showToast(msg: "下载成功");
      });
    } else {
      Fluttertoast.showToast(msg: "权限不足，下载取消");
    }
  }

  Future<bool> _beforeDownloadSong(AbstractSong song) async {
    String playUrl = song.playUrl;
    if (playUrl == null || playUrl.isEmpty) {
      AbstractSong remoteSong = await request.getSong(song);
      String rPlayUrl = remoteSong.playUrl;
      if (rPlayUrl == null || rPlayUrl.isEmpty) {
        return false;
      }
      song.playUrl = rPlayUrl;
    }
    return true;
  }
}
